package com.sheng.project.mask;

import cn.hutool.core.util.StrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.Environment;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.List;

/**
 * @author liusheng
 * @date 2023/07/19
 */
@Component
public class LsAutoMask implements ApplicationContextAware {

    private static final Logger log = LoggerFactory.getLogger(LsAutoMask.class);

    private static final String STR = "********************************************************************************";

    private static volatile Environment env;

    public static void result(List<?> entityList) {
        if (!CollectionUtils.isEmpty(entityList) && !enableMask(entityList.get(0))) {
            for (Object entity : entityList) {
                result(entity);
            }
        }
    }

    private static boolean enableMask(Object entity) {
        Class<?> tClass = entity.getClass();
        AutoMask autoMask = (AutoMask) tClass.getAnnotation(AutoMask.class);
        if (autoMask != null && !StrUtil.isEmpty(autoMask.enable())) {
            if ("true".equals(autoMask.enable())) {
                return false;
            } else if (!"false".equals(autoMask.enable())) {
                String enable = env.getProperty(autoMask.enable());
                return !"true".equals(enable);
            }
        }
        return true;
    }

    public static void result(Object entity) {
        try {
            Class<?> tClass = entity.getClass();
            AutoMask autoMask = tClass.getAnnotation(AutoMask.class);
            String[] maskFields = autoMask.maskFields();
            for (String maskField : maskFields) {
                Field field = tClass.getDeclaredField(maskField);
                maskHandle(field, entity);
            }
        } catch (Exception e) {
            log.error("填充数据脱敏失败,{}", e.toString());
        }
    }

    public static void singleResult(Object entity) {
        try {
            Class<?> tClass = entity.getClass();
            AutoMask autoMask = tClass.getAnnotation(AutoMask.class);
            boolean falg = false;
            if (autoMask != null && !StrUtil.isEmpty(autoMask.enable())) {
                if ("true".equals(autoMask.enable())) {
                    falg = true;
                } else if (!"false".equals(autoMask.enable())) {
                    String enable = env.getProperty(autoMask.enable());
                    if ("true".equals(enable)) {
                        falg = true;
                    }
                }
            }
            if (falg) {
                String[] maskFields = autoMask.maskFields();
                for (String maskField : maskFields) {
                    Field field = tClass.getDeclaredField(maskField);
                    maskHandle(field, entity);
                }
            }
        } catch (Exception e) {
            log.error("填充数据脱敏失败,{}", e.toString());
        }
    }

    public static void maskHandle(Field field, Object obj) {
        try {
            field.setAccessible(true);
            String data = String.valueOf(field.get(obj));
            if (StrUtil.isNotEmpty(data) && StrUtil.isNotEmpty(data) && data.length() > 1) {
                StringBuilder stringBuilder = new StringBuilder(data);
                String cutValue = "";
                // 暂时统一使用长度判断加密
                if (data.length() >= 200) {
                    cutValue = stringBuilder.substring(100, 140);
                    stringBuilder.replace(100, 140, STR.substring(0, 4 + cutValue.length()));
                } else if (data.length() >= 100) {
                    cutValue = stringBuilder.substring(30, 70);
                    stringBuilder.replace(30, 70, STR.substring(0, 4 + cutValue.length()));
                } else if (data.length() >= 50) {
                    cutValue = stringBuilder.substring(3, 40);
                    stringBuilder.replace(3, 40, STR.substring(0, 4 + cutValue.length()));
                } else if (data.length() >= 25) {
                    cutValue = stringBuilder.substring(3, 22);
                    stringBuilder.replace(3, 22, STR.substring(0, 4 + cutValue.length()));
                } else if (data.length() >= 18) {
                    cutValue = stringBuilder.substring(6, 14);
                    stringBuilder.replace(6, 14, STR.substring(0, 4 + cutValue.length()));
                } else if (data.length() >= 11) {
                    cutValue = stringBuilder.substring(3, 7);
                    stringBuilder.replace(3, 7, STR.substring(0, 4 + cutValue.length()));
                } else if (data.length() >= 6) {
                    cutValue = stringBuilder.substring(3, data.length() - 1);
                    stringBuilder.replace(3, data.length() - 1, STR.substring(0, 4 + cutValue.length()));
                } else if (data.length() >= 3) {
                    cutValue = stringBuilder.substring(1, data.length() - 1);
                    stringBuilder.replace(1, data.length() - 1, STR.substring(0, 4 + cutValue.length()));
                } else {
                    cutValue = stringBuilder.substring(1, 2);
                    stringBuilder.replace(1, 2, STR.substring(0, 4 + cutValue.length()));
                }
                data = stringBuilder.toString();
                String encrypt = CryptUtil.encrypt(cutValue);
                field.set(obj, data + "@mask@" + encrypt);
            }
        } catch (IllegalAccessException var12) {
            log.error("填充数据脱敏失败,{}", var12.toString());
        }
    }

    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        if (env == null) {
            synchronized (LsAutoMask.class) {
                if (env == null) {
                    env = applicationContext.getBean(Environment.class);
                }
            }
        }
    }
}
